var net = require('net')
const actions = require('./actions')
var { Config } = require('./config')


/**
 *   mainServer 主监听程序， slave注册到slaveMap中， 通过心跳保持连接
 */
var slaveMap = new Map()

var mainServer = net.createServer(function (socket) {
    console.log("connected:")
    console.log('   local = %s:%s', socket.localAddress, socket.localPort)
    console.log('   remote = %s: %s', socket.remoteAddress, socket.remotePort)

    socket.setDefaultEncoding('utf-8')
    socket.setEncoding('utf-8')


    socket.on('close', function () {
        console.log('manServer: slave socket on close: %s', socket.slaveName)
        slaveMap.delete(socket.slaveName)
    })

    /**
     *  处理 slave端发过来的消息
     */
    socket.on('data', function (data) {
        var str = data.toString()
        console.log("<< %s: %s", socket.slaveName, str)
        // str = str.replace("\r\n","")
        var strss = str.split("\r\n")
        console.log("strss = ", strss)
        strss.filter((it) => { return !(it == '') }).forEach(function (item) {
            console.log("++ %s, %s", socket.slaveName, item)
            try {
                var cmd = JSON.parse(item)
                var action = cmd.Action;
                switch (action) {
                    // 注册消息
                    case 'REG':
                        socket.slaveName = cmd.name
                        socket.timeStamp = new Date().getTime()
                        var s = slaveMap.get(cmd.name)
                        if (s) {
                            s.destroy()
                        }
                        slaveMap.set(cmd.name, socket)
                        break;
                    // 心跳消息
                    case 'HBEAT':
                        socket.timeStamp = new Date().getTime()
                        break;
                    default:
                        break;
                }
            } catch (e) {
                console.log("++ error: " , e)
                if(socket.slaveName == undefined){
                     console.log("slavename is undefined, request msg error, to close socket")
                     socket.end()
                     socket.destroy()
                }else{
                    console.log("error msg from %s ", socket.slaveName)
                    // socket.end()
                    // socket.destroy()
                }
            }
        })

    })

    socket.on('error', function (error) {
        console.log('mainServer: on error: %s , %s', error.message, socket.slaveName)
        slaveMap.delete(socket.slaveName)
        socket.destroy()
    })

    socket.on('end', function () {
        console.log("mainServer: on end %s", socket.slaveName)
    })
})

mainServer.listen(Config.serverPort, function () {
    console.log("mainServer start listening ", mainServer.address())
})


/**
 *   dataServer 数据监听服务， slave主动连接dataServer, 形成数据通道
 */
var dataSocketMap = new Map()
var dataServer = net.createServer(function (socket) {
    /**
     *  slave主动连接时，携带一个ID编号， 通过这个ID编号，将代理socke与数据socket关联
     */
    socket.once('data', function (data) {

        // RespLink消息
        var str = data.toString()
        str = str.replace("\r\n", "")
        console.log('dataServer on once :%s', str)
        var cmd = JSON.parse(str)
        var id = cmd.id
        var slaveName = cmd.name
        var port = cmd.port
        dataSocketMap.set(id, socket)
        socket.proxyId = id

        var slaveSocket = slaveMap.get(slaveName)
        var confirm = new actions.RESPCONFIRM(id, port)
        slaveSocket.write(JSON.stringify(confirm) + "\r\n");
        console.log(">> slave %s", JSON.stringify(confirm))


        addProxyMethd(proxySocketMap.get(id))
    })
})

dataServer.listen(Config.serverDataPort, function () {
    console.log("dataServer begin listen on %s", Config.serverDataPort)
})


var sequence = 1;
var proxySocketMap = new Map()
var proxyServerMap = new Map()
function proxy(port, slaveName, toPort) {
    var proxyServer = net.createServer(function (proxySocket) {

        console.log("proxyServer: conneting port %s", port)
        console.log('   local = %s:%s', proxySocket.localAddress, proxySocket.localPort)
        console.log('   remote = %s: %s', proxySocket.remoteAddress, proxySocket.remotePort)


        var id = getID({ port, slaveName, toPort, sequence })
        console.log("proxy id ::%s", id)
        sequence = sequence + 1

        var reqLink = new actions.REQLINK(id, toPort)
        var slaveSocket = slaveMap.get(slaveName)

        proxySocket.once("error", function (err) {
            console.log("proxySocket once Error :%", err.message)
            console.log("proxySocket once Error :", err.message)
            proxySocket.destroy()
            if (proxySocketMap.has(id)) {
                proxySocketMap.delete(id)
            }
        })

        if (slaveSocket) {
            slaveSocket.write(JSON.stringify(reqLink) + "\r\n")
            proxySocketMap.set(id, proxySocket)
            proxySocket.proxyId = id;
        } else {
            console.error("proxyServer: slave %s don't connected mainServer", slaveName)
            proxySocket.end()
            proxySocket.destroy()
        }
    })

    proxyServer.listen(port, function () {
        console.log('proxyServer start listening on %s to %s:%s', port, slaveName, toPort)
    })
    proxyServerMap.set("proxy:" + port + ":" + slaveName + ":" + toPort, proxyServer)
    proxyServer.on("error", function (error) {
        console.log("proxyServer onError ", error)
    })

    return proxyServer;
}


function addProxyMethd(proxySocket) {
    let id = proxySocket.proxyId;
    let dataSocket = dataSocketMap.get(id)
    proxySocket.on('data', function (data) {
        // console.log(" >> proxy %s, %s", id, data.length)
        dataSocket.write(data)
    })

    proxySocket.on('close', function () {
        console.log('proxySocket onClose %s', id)
        proxySocketMap.delete(id)
        dataSocket.end()

    })

    proxySocket.on('error', function (err) {
        console.log('proxySocket on error [%s] %s', id, err.message)
        console.log('proxySocket on error', err)
        proxySocketMap.delete(id)
        proxySocket.destroy()

        dataSocket.end()
        dataSocket.destroy()

    })


    dataSocket.on('data', function (data) {
        // console.log("<< dataSocket  %s, %s", id, data.length)
        proxySocket.write(data)
    })

    dataSocket.on('close', function () {
        console.log('datasocket onClose %s', id)
        dataSocketMap.delete(id)

        if (proxySocketMap.has(id)) {
            proxySocket.end()
            proxySocketMap.delete(id)
        }
    })

    dataSocket.on('error', function (err) {
        console.log('proxySocket on error [%s] %s', id, err.message)
        dataSocketMap.delete(id)
        dataSocket.destroy()

        if (proxySocketMap.has(id)) {
            proxySocket.end()
            proxySocket.destroy()
            proxySocketMap.delete(id)
        }
    })
}


// proxy(4600, 'ub01', 4500)
// proxy(4700, 'ub01', 4500)
// ProxyConfig.forEach(function( item){
//     const {port, slaveName, toPort} = item
//     proxy(port, slaveName, toPort)
// })

var proxyConfigMap = new Map()

var proxyjson = require('./proxy.json')
proxyjson.forEach(function (item) {
    let id = getID(item)
    proxyConfigMap.set(id, item)
    const { port, slaveName, toPort } = item
    proxy(port, slaveName, toPort)
})

function getID(configItem) {
    const { port, slaveName, toPort, sequence } = configItem
    return "proxy:" + port + ":" + slaveName + ":" + toPort + (sequence ? "-" + sequence : "")
}










